import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketAddress;
import java.sql.SQLException;
import java.util.ArrayList;


/**
 * ServerWorker -- Threaded handle of new requests
 */

public class ServerWorker implements Runnable {
	private Socket client;
	private PrintWriter os = null;

	public ServerWorker(Socket s) {
		this.client = s;
	}
	
	
		// TODO Auto-generated constructor stub
    	
    	//switching logic based on the desired operation
    	//String operation;
    	
    	//if (operation.equalsIgnoreCase("login"))
    	//String clientusername = "";
    	//read packet from user, save as clientusername
    	//String clientip = "";
    	//read IP from user, save as clientip
    	//String[][] clientfriends = HandleLogin(clientusername, clientip);
    	

	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	@Override
	public void run() {
		System.out.println("New worker created");
	    String line;
	    BufferedReader in = null;
	    //PrintWriter out = null;
	    try{
	      in = new BufferedReader(new 
	        InputStreamReader(client.getInputStream()));
	      //out = new 
	      //  PrintWriter(client.getOutputStream(), true);
	    } catch (IOException e) {
	      System.out.println("in or out failed");
	      return;
	    }
	    
	    //Think we might need something else for getting IP and port
	    //getInetAddr seems to get IP but not port
	    SocketAddress addr = client.getRemoteSocketAddress();

	    String msg = "";
	    ArrayList<String> data = new ArrayList<String>();
	    try {
	    	while(true){
			    line = in.readLine();
			    if(line.equals("{}") || line == null || line.equals("null")) break;
			    System.out.println("<"+line);
			    if(msg=="") msg = line;
			    else data.add(line);
	    	}
		} catch (IOException e) {
		    System.out.println("Read failed");
		    return;
		}
	    
	    try {
			process(msg, data, addr);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private void process(String msg, ArrayList<String> data, SocketAddress addr)
			throws ClassNotFoundException, SQLException, IOException {
		ServerDB db = new ServerDB();
		
		try {
			os = new PrintWriter(client.getOutputStream(), true);
		} catch (IOException e) {
			e.printStackTrace();
			return; //Exit if can't write to client
		}
		
		String result = "-1";
		boolean res = false;
		switch(msg) {
			case "login": //Username, Password
				if(data.size()!=3) {
					//System.out.println(data.size());
					//System.out.println(data.get(0));
					//System.out.println(data.get(1));
					//System.out.println(data.get(2));
					sendClose("Login requires 3 params");
					break;
				}
				String usr = data.get(0);
				int port = Integer.parseInt(data.get(2));
				res = db.auth(usr, data.get(1));
				
				if(!res) {
					sendError("Authorization error");
					break;
				}
				
				res = db.setLogin(usr, port, addr);
				
				if(!res) {
					sendError("Could not log in.");
					break;
				}
				db.sendFriendsList(usr, os);
				client.close();
				db.sendUpdates("online", usr, client);
				break;
			
			case "logout": //User
				res = db.logout(data.get(0));
				result = (res)?"true":"false";
				sendClose(result);
				client.close();
				db.sendUpdates("offline", data.get(0), client);
				break;
			
			case "addfriend": //Username, Friend's Username
				if(data.size()!=2) sendClose("Addfriend requires 2 params");
				res = db.addfriend(data.get(0), data.get(1), os);
				client.close();
				db.sendUpdate("online", data.get(0), data.get(1));
				break;
				
			case "exists": //Username
				res = db.userExists(data.get(0));
				result = (res)?"true":"false";
				sendClose(result);
				break;
			
			case "changepwd": //Username, NewPassword ?OldPassword
				res = db.changePwd(data.get(0), data.get(1));
				result = (res)?"true":"false";
				sendClose(result);
				break;
				
			case "register": //Username, Password
				res = db.register(data.get(0), data.get(1), addr);
				result = (res)?"true":"false";
				sendClose(result);
				break;
			
			case "removefriend": //Username, Friend's Username
				db.removefriend(data.get(0), data.get(1));
				sendClose("true");
				client.close();
				db.sendUpdate("offline", data.get(0), data.get(1));
				break;
			
			case "abomb":
				sendError("Boom.");
				break;
				
			default:
				sendError("Unknown command.");
				break;
		}
	}
	
	private void sendError(String err) {
		sendClose(err, true);	
	}
	
	private void sendClose(String msg) {
		sendClose(msg, false);	
	}
	
	private void sendClose(String msg, Boolean error) {
		if(os==null) return;
		if(error) os.println("Error");
		System.out.println(">> "+msg);
		os.println(msg);
		os.close();
	}	
}
